/*
 *  HeatEquation
 *
 *  Copyright (c) 2003 Satimage. All rights reserved.
 *
 */
#include "SimpleOSL.h"
//#include <iostream.h>


OSErr DefaultOSLAccessorProc(DescType desiredClass, const AEDesc* container,DescType containerClass, DescType form,const AEDesc* selectionData, AEDesc* value, long /*refCon*/){
	switch(desiredClass){
	case cProperty:
		if (selectionData->descriptorType == typeType){
			AEGetDescData(selectionData,&value->descriptorType,4);
			value->dataHandle=0;
			return 0;
		}
		else
			return errAEAccessorNotFound;
		break;
	default :
		return errAEAccessorNotFound;
	}
}

DescType GetDesiredType(const AppleEvent &message){
	DescType theType = typeWildCard;
	AEDescList types;
	if (AEGetParamDesc(&message, keyAERequestedType, typeAEList, &types) == 0) {
		DescType theAEKeyword,typeCode;
		long actualSize;
		AEGetNthPtr(&types,1,typeType,&theAEKeyword,&typeCode,&theType,4,&actualSize);
		AEDisposeDesc(&types);
	}
	return theType;
}

OSErr GetParamError(OSErr err,const AppleEvent* message,AppleEvent* reply){
   if(err){
	AEDesc d;
	AEGetParamDesc(message,keyDirectObject,typeWildCard,&d);
	AEPutParamDesc(reply,kOSAErrorOffendingObject,&d);
	AEDisposeDesc(&d);
	return err;
   }
   return err;
}
pascal OSErr AppleEventHandlerSet(const AppleEvent* message,AppleEvent* reply, long){
	AEDesc theDirectParameter,token;
	OSErr err=AEGetParamDesc(message, keyDirectObject,typeWildCard, &theDirectParameter);
	if(err)
	    return err;
	err=AEResolve(&theDirectParameter, kAEIDoMinimum, &token);
	AEDisposeDesc(&theDirectParameter);
	if(err)
	    return err;
	AEDesc AEData={typeNull,0};
	err=AEGetParamDesc(message, keyAEData, typeWildCard, &AEData);
	if(err)
	    return err;
	if(token.descriptorType=='Prop' || token.descriptorType=='qpro' || token.descriptorType=='prop'){
	    	if(AEData.descriptorType!=typeAERecord){
		    AEDisposeDesc(&AEData);
		    return errAETypeError;
		}
		AEDesc result={typeNull,0};
		DescType key;
		OSErr err1=0;
		for(int i=1;;i++){
			AEDisposeDesc(&result);
			err1=AEGetNthDesc(&AEData ,i,typeWildCard,&key,&result);
			if(err1)
				break;
			err1=gAESetProc(key,result);
		}
	}
	else{
	
	    err=gAESetProc(token.descriptorType,AEData);
	    if(err)
		err=GetParamError( err,message, reply);
	}
	AEDisposeDesc(&AEData);
	return err;
}

pascal OSErr AppleEventHandlerGet(const AppleEvent* message,AppleEvent* reply, long){
	AEDesc theDirectParameter,token;
	OSErr err=AEGetParamDesc(message, keyDirectObject,typeWildCard, &theDirectParameter);
	if(err)
	    return err;
	err=AEResolve(&theDirectParameter, kAEIDoMinimum, &token);
	AEDisposeDesc(&theDirectParameter);
	if(err)
	    return err;
	AEDesc result={typeNull,0};
	DescType typeCode;
	long actualSize;
	AEGetParamPtr(message,keyAERequestedType,typeType,&typeCode,&result.descriptorType,4,&actualSize);
	result.descriptorType=GetDesiredType(*message);
	if(token.descriptorType=='Prop' || token.descriptorType=='qpro' || token.descriptorType=='prop'){
	    if(!gPropertyListCount)
		return errAENoSuchObject;
	    AECreateList(0,0,true,&result);
	    for(int i=0;i<gPropertyListCount;i++){
		AEDesc d={typeNull,0};
		OSErr dummerr=gAEGetProc(gPropertyList[i],d);
		if(dummerr==0){
		    AEPutKeyDesc(&result,gPropertyList[i],&d);
		    AEDisposeDesc(&d);
		}
	    }
	}else
	    err=gAEGetProc(token.descriptorType,result);
	if(!err)
	    AEPutParamDesc(reply,keyAEResult,&result);
	AEDisposeDesc(&result);
	return err;
}

OSErr InstallOSL(){
    AEObjectInit();
    AEInstallObjectAccessor(cProperty, typeNull,NewOSLAccessorUPP(DefaultOSLAccessorProc), 0, false);
    AEInstallEventHandler(kAECoreSuite, kAEGetData,NewAEEventHandlerUPP(AppleEventHandlerGet), 0, false);
    AEInstallEventHandler(kAECoreSuite, kAESetData,NewAEEventHandlerUPP(AppleEventHandlerSet), 0, false);
    return 0;
}
//Tread stuff
ThreadID threadID = 0;

struct EventHandlerParams{
	AppleEvent message;
	AppleEvent reply;
	long refcon;
	AEEventHandlerUPP handler;
	OSErr err;
};

EventHandlerParams gEventHandlerParams;

struct EventInfo{
	long refcon;
	AEEventHandlerUPP handler;
};


voidPtr ComputeEntry(void * threadParam){
	gEventHandlerParams.err=0;
	gEventHandlerParams.err=InvokeAEEventHandlerUPP(&gEventHandlerParams.message,&gEventHandlerParams.reply,
		gEventHandlerParams.refcon,gEventHandlerParams.handler);
   threadID = 0;
   return 0;
}

void CopyDescToReply(AppleEvent* dumreply,AppleEvent* reply){
	long n;
	OSErr err=AECountItems(dumreply,&n);
	if(err)
		return;
	for(int i=1;i<=n;i++){
		AEKeyword theAEKeyword;
		AEDesc d;
		err=AEGetNthDesc(dumreply,i,typeWildCard,&theAEKeyword,&d);
		if(err)
			continue;
		AEPutParamDesc(reply,theAEKeyword,&d);
		AEDisposeDesc(&d);
	}
}


pascal OSErr AELauchThread(const AppleEvent* message,AppleEvent* reply, long refcon){
   OSErr err=0;
   static ThreadEntryTPP threadEntry=NewThreadEntryUPP(ComputeEntry);
    if(threadID){
        char* s="A thread is still running";
		AEPutParamPtr(reply,keyErrorString,typeChar,s,strlen(s));
		return 1;
    }
	EventInfo* evi=(EventInfo*)refcon;
	gEventHandlerParams.handler=evi->handler;
	gEventHandlerParams.refcon=evi->refcon;
	if(!gEventHandlerParams.handler)
		return errAEEventNotHandled;
	AEDuplicateDesc(message,&gEventHandlerParams.message);
	AECreateList(0,0,true,&gEventHandlerParams.reply);
	err=NewThread(kCooperativeThread, threadEntry,&gEventHandlerParams,0,kCreateIfNeeded,0,&threadID);
	YieldToAnyThread();
	if(threadID==0){
		CopyDescToReply(&gEventHandlerParams.reply,reply);
		AEDisposeDesc(&gEventHandlerParams.reply);
		AEDisposeDesc(&gEventHandlerParams.message);
	}
	return gEventHandlerParams.err;
}

pascal OSErr AEResume(const AppleEvent* message,AppleEvent* reply, long threaded){
	char* s="Program is not running";
	if(!threadID){
	    AEPutParamPtr(reply,keyErrorString,typeChar,s,strlen(s));
	    return 2;
	}
	YieldToAnyThread();
	if(threadID==0){
		CopyDescToReply(&gEventHandlerParams.reply,reply);
		AEDisposeDesc(&gEventHandlerParams.reply);
		AEDisposeDesc(&gEventHandlerParams.message);
	}
	return gEventHandlerParams.err;
}

OSErr  AEInstallThreadedEventHandler(AEEventClass theAEEventClass, AEEventID theAEEventID, AEEventHandlerUPP handler,
		long handlerRefcon, Boolean isSysHandler){
	static AEEventHandlerUPP AELauchThreadUPP=NewAEEventHandlerUPP(AELauchThread);
	static AEEventHandlerUPP AEResumeUPP=0;
	if(!AEResumeUPP){
		AEResumeUPP=NewAEEventHandlerUPP(AEResume);
		AEInstallEventHandler('SAMP', 'RESU',AEResumeUPP, 0, false);
	}
	EventInfo *evi=new EventInfo;
	evi->handler=handler;
	evi->refcon=handlerRefcon;
	return AEInstallEventHandler(theAEEventClass, theAEEventID,AELauchThreadUPP, long(evi), false);
}

